﻿using System;
using System.Collections.Generic;
using GeoAPI.Geometries;

namespace NetTopologySuite.Index.Strtree
{
	public class SIRtree<TItem> : AbstractSTRtree<Interval, TItem>
	{
		public SIRtree() : this(10)
		{
		}

		public SIRtree(int nodeCapacity) : base(nodeCapacity)
		{
		}

		protected override AbstractNode<Interval, TItem> CreateNode(int level)
		{
			return new SIRtree<TItem>.AnonymousAbstractNodeImpl(level);
		}

		public void Insert(double x1, double x2, TItem item)
		{
			base.Insert(new Interval(System.Math.Min(x1, x2), System.Math.Max(x1, x2)), item);
		}

		public IList<TItem> Query(double x)
		{
			return this.Query(x, x);
		}

		public IList<TItem> Query(double x1, double x2)
		{
			return base.Query(new Interval(System.Math.Min(x1, x2), System.Math.Max(x1, x2)));
		}

		protected override AbstractSTRtree<Interval, TItem>.IIntersectsOp IntersectsOp
		{
			get
			{
				return SIRtree<TItem>.IntersectsOperation;
			}
		}

		protected override IComparer<IBoundable<Interval, TItem>> GetComparer()
		{
			return SIRtree<TItem>.Comparator;
		}

		private static readonly IComparer<IBoundable<Interval, TItem>> Comparator = new SIRtree<TItem>.AnnonymousComparerImpl();

		private static readonly AbstractSTRtree<Interval, TItem>.IIntersectsOp IntersectsOperation = new SIRtree<TItem>.AnonymousIntersectsOpImpl();

		private class AnnonymousComparerImpl : IComparer<IBoundable<Interval, TItem>>
		{
			public int Compare(IBoundable<Interval, TItem> o1, IBoundable<Interval, TItem> o2)
			{
				double centre = o1.Bounds.Centre;
				double centre2 = o2.Bounds.Centre;
				return centre.CompareTo(centre2);
			}
		}

		private class AnonymousIntersectsOpImpl : AbstractSTRtree<Interval, TItem>.IIntersectsOp
		{
			public bool Intersects(Interval aBounds, Interval bBounds)
			{
				return aBounds.Intersects(bBounds);
			}
		}

		private class AnonymousAbstractNodeImpl : AbstractNode<Interval, TItem>
		{
			public AnonymousAbstractNodeImpl(int nodeCapacity) : base(nodeCapacity)
			{
			}

			protected override Interval ComputeBounds()
			{
				Interval interval = null;
				foreach (IBoundable<Interval, TItem> boundable in base.ChildBoundables)
				{
					if (interval == null)
					{
						interval = new Interval(boundable.Bounds);
					}
					else
					{
						interval.ExpandToInclude(boundable.Bounds);
					}
				}
				return interval;
			}
		}
	}
}
